from typing import Annotated, Optional
from fastapi import Request, Depends
from fastapi.security.utils import get_authorization_scheme_param
from sqlalchemy import select
from slowapi.util import get_remote_address

from core.database import DBConnect
from core.models import Config, Member
from api.settings import api_settings
from api.v1.auth import oauth2_scheme
from api.v1.auth.jwt import JWT
from api.v1.service.member import MemberServiceAPI
from api.v1.models.auth import TokenPayload
from lib.slowapi import LimiterNoWarning


def get_request_member(
    token: Annotated[str, Depends(oauth2_scheme)],
    member_service: Annotated[MemberServiceAPI, Depends()]
) -> Optional[Member]:
    """
    REST_API 根据要求 JWT 通过令牌获取用户信息的函数

    Args:
        token (Annotated[str, Depends(oauth2_scheme)]): JWT 令牌
        member_service (Annotated[MemberServiceAPI, Depends()]): 用户信息服务

    Returns:
        Member: 用户信息对象或 None
    """
    payload: TokenPayload = JWT.decode_token(
        token,
        api_settings.ACCESS_TOKEN_SECRET_KEY
    )

    mb_id: str = payload.sub
    if mb_id is None:
        return None

    member = member_service.get_member(mb_id)
    return member


def limiter_key_func(request: Request) -> Optional[str]:
    """
    Limiter 当您创建实例时 key_func 要提供给因子的功能.
    None返回为 IP 地址(经理 IP)不限制请求.

    Args:
        request (Request): FastAPI Request 对象
    
    Returns:
        Optional[str]: 请求限制 IP 地址或 None
    """
    authorization = request.headers.get("Authorization")
    scheme, token = get_authorization_scheme_param(authorization)

    if not authorization or scheme.lower() != "bearer":
        return get_remote_address(request)

    with DBConnect().sessionLocal() as db:
        member_service = MemberServiceAPI(request, db)
        cf_admin = db.scalar(select(Config)).cf_admin

    member = get_request_member(token, member_service)
    if member.mb_id == cf_admin:
        return None

    return get_remote_address(request)


def get_cf_delay_sec_from_db():
    """
从数据库获取cf_delay_sec值
一个函数，返回用于创建Limiter实例的限制表达式。
以“n/t time”格式返回
-在t小时（以小时为单位为时间）内允许n次请求
      - time: second, minute, hour, day, month, year
      - documentation: https://limits.readthedocs.io/en/stable/quickstart.html#rate-limit-string-notation
    """
    with DBConnect().sessionLocal() as db:
        cf_delay_sec = db.scalar(select(Config)).cf_delay_sec
    limiter_expr = f"1/{cf_delay_sec} second"
    return limiter_expr


# 创建请求限制limiter实例
limiter = LimiterNoWarning(key_func=limiter_key_func)


@limiter.limit(
    get_cf_delay_sec_from_db,
    error_message="无法在太快的时间内连续发布帖子。",
)
def validate_slowapi_create_post(request: Request):
    """
    通过slowapi的Limiter验证帖子生成API请求超时的函数

    Args:
        request (Request): FastAPI Request 对象
    """
    pass